package health_system.health_system.service;

import health_system.health_system.entity.ChatMessage;
import health_system.health_system.entity.ChatRoom;
import health_system.health_system.entity.MessageReadStatus;
import health_system.health_system.entity.User;
import health_system.health_system.exception.ChatAccessDeniedException;
import health_system.health_system.exception.ChatMessageRecallException;
import health_system.health_system.repository.ChatMessageRepository;
import health_system.health_system.repository.ChatRoomRepository;
import health_system.health_system.repository.MessageReadStatusRepository;
import health_system.health_system.repository.UserRepository;
import jakarta.persistence.EntityNotFoundException;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class ChatMessageService {

    private final ChatMessageRepository chatMessageRepository;
    private final ChatRoomRepository chatRoomRepository;
    private final MessageReadStatusRepository messageReadStatusRepository;
    private final UserRepository userRepository;
//    private final NotificationService notificationService;
    private final FileStorageService fileStorageService;

    /**
     * 发送文本消息
     * 创建并保存一条文本消息
     */
    @Transactional
    public ChatMessage sendTextMessage(Long chatRoomId, Long senderId, String textContent, Long replyToMessageId) {
        ChatRoom chatRoom = getChatRoomById(chatRoomId);
        User sender = getUserById(senderId);
        
        // 验证发送者是否是聊天室的参与者
        validateChatRoomParticipant(chatRoom, sender);
        
        ChatMessage chatMessage = new ChatMessage();
        chatMessage.setChatRoom(chatRoom);
        chatMessage.setSender(sender);
        chatMessage.setMessageType(ChatMessage.MessageType.TEXT);
        chatMessage.setTextContent(textContent);
        chatMessage.setIsDeliveredToServer(true);
        chatMessage.setDeliveredAt(LocalDateTime.now());
        
        // 如果是回复其他消息
        if (replyToMessageId != null) {
            ChatMessage replyToMessage = getChatMessageById(replyToMessageId);
            chatMessage.setReplyToMessage(replyToMessage);
        }
        
        // 保存消息
        ChatMessage savedMessage = chatMessageRepository.save(chatMessage);
        
        // 为聊天室所有其他参与者创建消息阅读状态
        createReadStatusForParticipants(savedMessage);
        
        // 发送通知给其他参与者
        notifyMessageSent(savedMessage);
        
        return savedMessage;
    }
    
    /**
     * 发送媒体消息（图片、视频、音频、文件）
     */
    @Transactional
    public ChatMessage sendMediaMessage(Long chatRoomId, Long senderId, ChatMessage.MessageType messageType,
                                      byte[] mediaData, String fileName, Integer mediaDuration) throws IOException {
        ChatRoom chatRoom = getChatRoomById(chatRoomId);
        User sender = getUserById(senderId);
        
        // 验证发送者是否是聊天室的参与者
        validateChatRoomParticipant(chatRoom, sender);
        
        // 验证消息类型
        validateMediaMessageType(messageType);
        
        // 保存媒体文件并获取URL
        String mediaUrl = fileStorageService.storeMediaFile(mediaData, fileName, messageType.toString().toLowerCase());
        
        ChatMessage chatMessage = new ChatMessage();
        chatMessage.setChatRoom(chatRoom);
        chatMessage.setSender(sender);
        chatMessage.setMessageType(messageType);
        chatMessage.setMediaUrl(mediaUrl);
        chatMessage.setIsDeliveredToServer(true);
        chatMessage.setDeliveredAt(LocalDateTime.now());
        
        // 如果是音频或视频，设置持续时间
        if (messageType == ChatMessage.MessageType.AUDIO || messageType == ChatMessage.MessageType.VIDEO) {
            chatMessage.setMediaDuration(mediaDuration);
        }
        
        // 保存消息
        ChatMessage savedMessage = chatMessageRepository.save(chatMessage);
        
        // 为聊天室所有其他参与者创建消息阅读状态
        createReadStatusForParticipants(savedMessage);
        
        // 发送通知给其他参与者
        notifyMessageSent(savedMessage);
        
        return savedMessage;
    }
    
    /**
     * 撤回消息
     * 只能在发送后一定时间内撤回自己的消息
     */
    @Transactional
    public ChatMessage recallMessage(Long messageId, Long userId) {
        ChatMessage message = getChatMessageById(messageId);
        User user = getUserById(userId);
        
        // 验证是否是消息发送者
        if (!message.getSender().getId().equals(userId)) {
            throw new ChatAccessDeniedException("只能撤回自己发送的消息");
        }
        
        // 检查消息是否已经被撤回
        if (message.getIsRecalled()) {
            throw new ChatMessageRecallException("消息已被撤回");
        }
        
        // 检查是否超过了可撤回时间（例如2分钟）
        LocalDateTime recallDeadline = message.getCreatedAt().plusMinutes(2);
        if (LocalDateTime.now().isAfter(recallDeadline)) {
            throw new ChatMessageRecallException("消息发送超过2分钟，无法撤回");
        }
        
        // 标记消息为已撤回
        message.setIsRecalled(true);
        message.setRecalledAt(LocalDateTime.now());
        return chatMessageRepository.save(message);
    }
    
    /**
     * 批量撤回消息
     */
    @Transactional
    public List<ChatMessage> recallMessages(List<Long> messageIds, Long userId) {
        List<ChatMessage> messages = chatMessageRepository.findAllById(messageIds);
        List<ChatMessage> recalledMessages = new ArrayList<>();
        
        for (ChatMessage message : messages) {
            try {
                ChatMessage recalledMessage = recallMessage(message.getId(), userId);
                recalledMessages.add(recalledMessage);
            } catch (Exception e) {
                log.warn("无法撤回消息 ID: {}, 原因: {}", message.getId(), e.getMessage());
                // 继续处理其他消息
            }
        }
        
        return recalledMessages;
    }
    
    /**
     * 标记消息为已读
     */
    @Transactional
    public void markMessageAsRead(Long messageId, Long userId) {
        ChatMessage message = getChatMessageById(messageId);
        User user = getUserById(userId);
        
        // 检查用户是否是聊天室的参与者
        validateChatRoomParticipant(message.getChatRoom(), user);
        
        // 获取或创建阅读状态
        Optional<MessageReadStatus> existingStatus = messageReadStatusRepository.findByMessageAndUser(message, user);
        
        if (existingStatus.isPresent()) {
            MessageReadStatus status = existingStatus.get();
            if (!status.getIsRead()) {
                status.setIsRead(true);
                status.setReadAt(LocalDateTime.now());
                messageReadStatusRepository.save(status);
            }
        } else {
            MessageReadStatus newStatus = new MessageReadStatus();
            newStatus.setMessage(message);
            newStatus.setUser(user);
            newStatus.setIsRead(true);
            newStatus.setReadAt(LocalDateTime.now());
            messageReadStatusRepository.save(newStatus);
        }
    }
    
    /**
     * 标记聊天室中的所有消息为已读
     */
    @Transactional
    public void markAllMessagesAsRead(Long chatRoomId, Long userId) {
        ChatRoom chatRoom = getChatRoomById(chatRoomId);
        User user = getUserById(userId);
        
        // 检查用户是否是聊天室的参与者
        validateChatRoomParticipant(chatRoom, user);
        
        // 标记所有消息为已读
        messageReadStatusRepository.markAllMessagesAsReadInRoom(chatRoom, user);
    }
    
    /**
     * 标记多个消息为已读
     */
    @Transactional
    public void markMessagesAsRead(List<Long> messageIds, Long userId) {
        User user = getUserById(userId);
        
        // 验证所有消息是否属于用户有权访问的聊天室
        List<ChatMessage> messages = chatMessageRepository.findAllById(messageIds);
        for (ChatMessage message : messages) {
            validateChatRoomParticipant(message.getChatRoom(), user);
        }
        
        // 标记消息为已读
        messageReadStatusRepository.markMessagesAsRead(messageIds, user);
    }
    
    /**
     * 获取聊天室的消息历史（分页）
     */
    public Page<ChatMessage> getChatHistory(Long chatRoomId, Long userId, int page, int size) {
        ChatRoom chatRoom = getChatRoomById(chatRoomId);
        User user = getUserById(userId);
        
        // 检查用户是否是聊天室的参与者
        validateChatRoomParticipant(chatRoom, user);
        
        // 获取消息历史（按时间倒序，最新的消息在前面）
        Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createdAt"));
        return chatMessageRepository.findByChatRoomOrderByCreatedAtDesc(chatRoom, pageable);
    }
    
    /**
     * 获取未读消息数量
     */
    public Long getUnreadMessageCount(Long userId) {
        User user = getUserById(userId);
        return messageReadStatusRepository.countUnreadMessagesForUser(user);
    }
    
    /**
     * 获取特定聊天室的未读消息数量
     */
    public Long getUnreadMessageCountInRoom(Long chatRoomId, Long userId) {
        ChatRoom chatRoom = getChatRoomById(chatRoomId);
        User user = getUserById(userId);
        
        // 检查用户是否是聊天室的参与者
        validateChatRoomParticipant(chatRoom, user);
        
        return messageReadStatusRepository.countUnreadMessagesInRoom(user, chatRoom);
    }
    
    /**
     * 搜索消息
     */
    public List<ChatMessage> searchMessages(Long chatRoomId, Long userId, String searchTerm) {
        ChatRoom chatRoom = getChatRoomById(chatRoomId);
        User user = getUserById(userId);
        
        // 检查用户是否是聊天室的参与者
        validateChatRoomParticipant(chatRoom, user);
        
        return chatMessageRepository.searchMessages(chatRoom, searchTerm);
    }
    
    /**
     * 获取特定类型的消息
     */
    public List<ChatMessage> getMessagesByType(Long chatRoomId, Long userId, ChatMessage.MessageType messageType) {
        ChatRoom chatRoom = getChatRoomById(chatRoomId);
        User user = getUserById(userId);
        
        // 检查用户是否是聊天室的参与者
        validateChatRoomParticipant(chatRoom, user);
        
        return chatMessageRepository.findByChatRoomAndMessageTypeOrderByCreatedAtDesc(chatRoom, messageType);
    }
    
    /**
     * 获取所有媒体消息（图片、视频、音频、文件）
     */
    public List<ChatMessage> getAllMediaMessages(Long chatRoomId, Long userId) {
        ChatRoom chatRoom = getChatRoomById(chatRoomId);
        User user = getUserById(userId);
        
        // 检查用户是否是聊天室的参与者
        validateChatRoomParticipant(chatRoom, user);
        
        return chatMessageRepository.findAllMediaMessages(chatRoom);
    }
    
    /**
     * 获取置顶消息
     */
    public List<ChatMessage> getPinnedMessages(Long chatRoomId, Long userId) {
        ChatRoom chatRoom = getChatRoomById(chatRoomId);
        User user = getUserById(userId);
        
        // 检查用户是否是聊天室的参与者
        validateChatRoomParticipant(chatRoom, user);
        
        return chatMessageRepository.findByChatRoomAndIsPinnedTrue(chatRoom);
    }
    
    /**
     * 置顶/取消置顶消息
     */
    @Transactional
    public ChatMessage togglePinMessage(Long messageId, Long userId) {
        ChatMessage message = getChatMessageById(messageId);
        User user = getUserById(userId);
        
        // 检查用户是否是聊天室的参与者
        validateChatRoomParticipant(message.getChatRoom(), user);
        
        // 切换置顶状态
        boolean newPinnedStatus = !message.getIsPinned();
        message.setIsPinned(newPinnedStatus);
        
        if (newPinnedStatus) {
            message.setPinnedAt(LocalDateTime.now());
        } else {
            message.setPinnedAt(null);
        }
        
        return chatMessageRepository.save(message);
    }
    
    /**
     * 获取用户所有聊天室的最新消息
     */
    public List<ChatMessage> getLatestMessagesForUser(Long userId) {
        User user = getUserById(userId);
        return chatMessageRepository.findLatestMessagesForUser(user);
    }
    
    /**
     * 获取指定时间段内的消息
     */
    public List<ChatMessage> getMessagesBetweenDates(Long chatRoomId, Long userId, 
                                                  LocalDateTime startTime, LocalDateTime endTime) {
        ChatRoom chatRoom = getChatRoomById(chatRoomId);
        User user = getUserById(userId);
        
        // 检查用户是否是聊天室的参与者
        validateChatRoomParticipant(chatRoom, user);
        
        return chatMessageRepository.findByChatRoomAndCreatedAtBetweenOrderByCreatedAtAsc(
                chatRoom, startTime, endTime);
    }
    
    /**
     * 获取未送达的消息
     * 可用于客户端离线期间的消息同步
     */
    public List<ChatMessage> getUndeliveredMessages(Long userId) {
        User user = getUserById(userId);
        return chatMessageRepository.findUndeliveredMessagesForUser(user);
    }
    
    /**
     * 标记消息已送达服务器
     */
    @Transactional
    public void markMessagesAsDelivered(List<Long> messageIds) {
        chatMessageRepository.markMessagesAsDelivered(messageIds);
    }
    
    /**
     * 获取消息已读状态详情
     */
    public List<MessageReadStatus> getMessageReadStatuses(Long messageId) {
        ChatMessage message = getChatMessageById(messageId);
        return messageReadStatusRepository.findByMessage(message);
    }
    
    /**
     * 检查消息是否已被所有参与者阅读
     */
    public boolean isMessageReadByAll(Long messageId) {
        ChatMessage message = getChatMessageById(messageId);
        Long unreadCount = messageReadStatusRepository.countUnreadStatusesForMessage(message);
        return unreadCount == 0;
    }
    
    /**
     * 获取聊天室未读消息（仅未读）
     */
    public List<ChatMessage> getUnreadMessagesInRoom(Long chatRoomId, Long userId) {
        ChatRoom chatRoom = getChatRoomById(chatRoomId);
        User user = getUserById(userId);
        
        // 检查用户是否是聊天室的参与者
        validateChatRoomParticipant(chatRoom, user);
        
        return chatMessageRepository.findUnreadMessagesInRoom(chatRoom, user);
    }
    
    /**
     * 转发消息到其他聊天室
     */
    @Transactional
    public List<ChatMessage> forwardMessages(List<Long> messageIds, List<Long> targetChatRoomIds, Long userId) {
        User sender = getUserById(userId);
        List<ChatMessage> forwardedMessages = new ArrayList<>();
        
        List<ChatMessage> originalMessages = chatMessageRepository.findAllById(messageIds);
        List<ChatRoom> targetChatRooms = chatRoomRepository.findAllById(targetChatRoomIds);
        
        for (ChatRoom targetChatRoom : targetChatRooms) {
            // 验证用户是否是目标聊天室的参与者
            validateChatRoomParticipant(targetChatRoom, sender);
            
            for (ChatMessage originalMessage : originalMessages) {
                ChatMessage forwardedMessage = new ChatMessage();
                forwardedMessage.setChatRoom(targetChatRoom);
                forwardedMessage.setSender(sender);
                forwardedMessage.setMessageType(originalMessage.getMessageType());
                forwardedMessage.setTextContent(originalMessage.getTextContent());
                forwardedMessage.setMediaUrl(originalMessage.getMediaUrl());
                forwardedMessage.setMediaDuration(originalMessage.getMediaDuration());
                forwardedMessage.setIsDeliveredToServer(true);
                forwardedMessage.setDeliveredAt(LocalDateTime.now());
                
                // 保存转发的消息
                ChatMessage savedMessage = chatMessageRepository.save(forwardedMessage);
                
                // 为聊天室所有其他参与者创建消息阅读状态
                createReadStatusForParticipants(savedMessage);
                
                // 发送通知给其他参与者
                notifyMessageSent(savedMessage);
                
                forwardedMessages.add(savedMessage);
            }
        }
        
        return forwardedMessages;
    }
    
    /**
     * 删除消息（仅数据库标记，不删除实际记录）
     */
    @Transactional
    public void deleteMessage(Long messageId, Long userId) {
        ChatMessage message = getChatMessageById(messageId);
        User user = getUserById(userId);
        
        // 验证是否是消息发送者
        if (!message.getSender().getId().equals(userId)) {
            throw new ChatAccessDeniedException("只能删除自己发送的消息");
        }
        
        // 标记消息为已撤回（作为删除的实现）
        message.setIsRecalled(true);
        message.setRecalledAt(LocalDateTime.now());
        message.setTextContent("此消息已被删除");
        chatMessageRepository.save(message);
    }
    
    /**
     * 创建消息阅读状态
     */
    private void createReadStatusForParticipants(ChatMessage message) {
        // 获取聊天室所有参与者
        Set<User> participants = message.getChatRoom().getParticipants();
        
        for (User participant : participants) {
            // 发送者自己的消息自动标记为已读
            boolean isRead = participant.getId().equals(message.getSender().getId());
            LocalDateTime readAt = isRead ? LocalDateTime.now() : null;
            
            MessageReadStatus readStatus = new MessageReadStatus();
            readStatus.setMessage(message);
            readStatus.setUser(participant);
            readStatus.setIsRead(isRead);
            readStatus.setReadAt(readAt);
            
            messageReadStatusRepository.save(readStatus);
        }
    }
    
    /**
     * 发送新消息通知
     */
    private void notifyMessageSent(ChatMessage message) {
        Set<User> recipients = message.getChatRoom().getParticipants().stream()
                .filter(p -> !p.getId().equals(message.getSender().getId()))
                .collect(Collectors.toSet());
        
        for (User recipient : recipients) {
            try {
                String senderName = message.getSender().getUsername();
                String contentPreview = getMessageContentPreview(message);
                String chatName = getChatRoomName(message.getChatRoom(), recipient);
                
                log.info("发送消息通知给用户: {}, 来自: {}, 聊天: {}, 内容: {}", 
                         recipient.getId(), senderName, chatName, contentPreview);
                
                // 通知实现可以通过WebSocket、推送通知等方式
//                notificationService.sendChatMessageNotification(recipient, message);
            } catch (Exception e) {
                log.error("发送消息通知失败，接收者ID: {}, 消息ID: {}", recipient.getId(), message.getId(), e);
            }
        }
    }
    
    /**
     * 获取消息内容预览
     */
    private String getMessageContentPreview(ChatMessage message) {
        switch (message.getMessageType()) {
            case TEXT:
                String text = message.getTextContent();
                if (text.length() > 20) {
                    return text.substring(0, 20) + "...";
                }
                return text;
            case IMAGE:
                return "[图片]";
            case VIDEO:
                return "[视频]";
            case AUDIO:
                return "[语音]";
            case FILE:
                return "[文件]";
            case LOCATION:
                return "[位置]";
            case CONTACT:
                return "[联系人]";
            case SCREEN_SHARE:
                return "[屏幕共享]";
            default:
                return "[消息]";
        }
    }
    
    /**
     * 获取聊天室显示名称
     */
    private String getChatRoomName(ChatRoom chatRoom, User currentUser) {
        if (chatRoom.getChatType() == ChatRoom.ChatType.GROUP) {
            return chatRoom.getGroupName();
        } else {
            // 私聊显示对方的名字
            return chatRoom.getParticipants().stream()
                    .filter(p -> !p.getId().equals(currentUser.getId()))
                    .findFirst()
                    .map(User::getUsername)
                    .orElse("私聊");
        }
    }
    
    /**
     * 验证媒体消息类型
     */
    private void validateMediaMessageType(ChatMessage.MessageType messageType) {
        if (messageType == ChatMessage.MessageType.TEXT) {
            throw new IllegalArgumentException("文本消息请使用sendTextMessage方法");
        }
        
        List<ChatMessage.MessageType> validMediaTypes = List.of(
                ChatMessage.MessageType.IMAGE, ChatMessage.MessageType.VIDEO,
                ChatMessage.MessageType.AUDIO, ChatMessage.MessageType.FILE);
                
        if (!validMediaTypes.contains(messageType)) {
            throw new IllegalArgumentException("不支持的媒体消息类型: " + messageType);
        }
    }
    
    /**
     * 验证用户是否是聊天室的参与者
     */
    private void validateChatRoomParticipant(ChatRoom chatRoom, User user) {
        if (!chatRoom.getParticipants().contains(user)) {
            throw new ChatAccessDeniedException("用户不是聊天室的参与者");
        }
    }
    
    /**
     * 获取聊天室
     */
    private ChatRoom getChatRoomById(Long chatRoomId) {
        return chatRoomRepository.findById(chatRoomId)
                .orElseThrow(() -> new EntityNotFoundException("聊天室不存在，ID: " + chatRoomId));
    }
    
    /**
     * 获取用户
     */
    private User getUserById(Long userId) {
        return userRepository.findById(userId)
                .orElseThrow(() -> new EntityNotFoundException("用户不存在，ID: " + userId));
    }
    
    /**
     * 获取消息
     */
    private ChatMessage getChatMessageById(Long messageId) {
        return chatMessageRepository.findById(messageId)
                .orElseThrow(() -> new EntityNotFoundException("消息不存在，ID: " + messageId));
    }

    /**
     * 获取当前用户与指定用户之间的聊天消息历史（分页）
     */
    public Page<ChatMessage> getChatHistoryWithUser(Long currentUserId, Long friendId, int page, int size) {
        User currentUser = getUserById(currentUserId);
        User friend = getUserById(friendId);
        
        // 查找当前用户与好友之间的聊天室
        ChatRoom chatRoom = chatRoomRepository.findOneOnOneChatRoom(currentUser, friend)
                .orElseThrow(() -> new EntityNotFoundException("找不到与该用户的聊天记录"));
        
        // 获取聊天室的消息历史
        Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createdAt"));
        return chatMessageRepository.findByChatRoomOrderByCreatedAtDesc(chatRoom, pageable);
    }
} 